// vi:si:et:sw=4:sts=4:ts=4
package cat.hex.trainoid;

import java.util.ArrayList;
import java.util.Date;

import android.content.Context;
import android.database.SQLException;
import android.location.Location;
import android.util.Log;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;

public class Track
{
	public static final String CREATED_AT_FORMAT = "yyyy/MM/dd";

	protected static String name;
	protected static String body;
	protected static String type;
	protected static Date created_at;
	private static long mTrackId;

	protected ArrayList<Location> path;
	protected ArrayList<GeoPoint> pathPositions;

	protected Location lastLocation;

	protected long totalDistance = 0;
	protected long totalTime = 0;
	protected long totalMovingTime = 0;

	private DbAdapter mDbHelper;
	private final Context mCtx;

	static final private String tag = "track"; // for Log

	public Track(long trackId, Context ctx)
	{
		mCtx = ctx;
		mTrackId = trackId;

		lastLocation = null;

		mDbHelper = new DbAdapter(mCtx);

		readGPSPositions();

		calculateTotalDistance();
		calculateTotalTime();
		calculateTotalMovingTime();
	}

	public Track(Context ctx)
	{
		this.mCtx = ctx;

		mDbHelper = new DbAdapter(mCtx);
		path = new ArrayList<Location>();
		pathPositions = new ArrayList<GeoPoint>();
	}

	private void readGPSPositions()
	{
		if (mTrackId < -1)
			Log.d(tag, "readGPSPositions mTrackId is null (< -1), nothing to do!");

		GeoPoint point;

		mDbHelper.openReadonly();

		if (path != null)
			path.clear();
		else
			path= new ArrayList<Location>();

		path = mDbHelper.getTrackLocationPath(mTrackId);

		if (pathPositions != null)
			pathPositions.clear();
		else
			pathPositions = new ArrayList<GeoPoint>();

		for (int i = 0; i < path.size(); i++)
		{		
			point = new GeoPoint((int)(path.get(i).getLatitude()*1e6), (int)(path.get(i).getLongitude()*1e6));

			pathPositions.add(point);
		}

		mDbHelper.close();
	}

	public float getTotalTime()
	{
		return totalTime;
	}

	public float getTotalMovingTime()
	{
		return totalMovingTime;
	}

	public float getTotalDistance()
	{
		return totalDistance;
	}

	protected void calculateTotalDistance()
	{
		totalDistance = 0;

		for (int i = 0; i < (path.size() - 1); i++)
			totalDistance += (float)(path.get(i).distanceTo(path.get(i+1)));
	}

	protected void calculateTotalTime()
	{
		if (path.size() > 1)
			totalTime = path.get(path.size()-1).getTime() - path.get(0).getTime();
		else
			totalTime = 0;
	}

	protected void calculateTotalMovingTime()
	{
		totalMovingTime = 0;

		for (int i = 0; i < (path.size() - 1); i++)
			if (path.get(i).getSpeed() > 0)
				totalMovingTime += path.get(i+1).getTime() - path.get(i).getTime();
	}

	protected void centerMap(MapController mMapController)
	{
		int size = path.size();
		double maxLatitude;
		double minLatitude;
		double maxLongitude;
		double minLongitude;

		Location it;
		GeoPoint center = null;

		if (size >= 1)
		{
			it = path.get(0);
			maxLatitude = it.getLatitude();
			minLatitude = it.getLatitude();

			maxLongitude = it.getLongitude();
			minLongitude = it.getLongitude();

			for (int i = 1; i < size; i++)
			{
				it = path.get(i);

				if (maxLatitude < it.getLatitude())
					maxLatitude = it.getLatitude();

				if (minLatitude > it.getLatitude())
					minLatitude = it.getLatitude();

				if (maxLongitude < it.getLongitude())
					maxLongitude = it.getLongitude();

				if (minLongitude > it.getLongitude())
					minLongitude = it.getLongitude();
			}

			// Center the Map
			center = new GeoPoint((int)(((maxLatitude + minLatitude)/2)*1e6), (int)(((maxLongitude + minLongitude)/2)*1e6));
			mMapController.animateTo(center);

			// Adjust the zoom level
			mMapController.zoomToSpan((int)(Math.abs( minLatitude - maxLatitude )*1e6), (int)(Math.abs( minLongitude - maxLongitude )*1e6));
		}
	}

	public void addPosition(Location location)
	{		
		if (lastLocation != null)
		{
			totalDistance += lastLocation.distanceTo(location);
			totalTime = location.getTime() - path.get(0).getTime(); // now we get minutes

			if (location.getSpeed() > 0)
				totalMovingTime += location.getTime() - path.get(path.size()-1).getTime();
		}

		GeoPoint geopoint = new GeoPoint((int)(location.getLatitude()*1e6), (int)(location.getLongitude()*1e6));

		pathPositions.add(geopoint);
		path.add(location);
		lastLocation = location;
	}

	public int getTrackSize()
	{
		return path.size();
	}

	public ArrayList<GeoPoint> getGeoPath()
	{
		return pathPositions;
	}

	public ArrayList<Location> getPath()
	{
		return path;
	}

	public long getTrackId()
	{
		return mTrackId;
	}

	public void setPath(ArrayList<Location> newPath)
	{
		if (newPath == null)
			return;

		if (path != null)
			path.clear();

		int max = newPath.size();
		for (int i = 0; i < max; i++)
			path.add(newPath.get(i));
	}
	
	public void readRecordingPath()
	{
		mDbHelper.open();
		setPath(mDbHelper.getTrackLocationPath(GPSReceiver.RECORDING_TRACK_ID));
		mDbHelper.close();
	}

	public boolean saveTrack()
	{
		mDbHelper.open();

		mTrackId = mDbHelper.createTrack();

		mDbHelper.updateTrackName(mTrackId, "New Track id: " + mTrackId);

		try
		{
			float distance = 0;
			int last_for_distance = (path.size() - 1);

			mDbHelper.beginTransaction();
			for (int i = 0; i < path.size(); i++)
			{
				mDbHelper.createPosition(mTrackId, path.get(i));
				if (i < last_for_distance)
					distance += (float)(path.get(i).distanceTo(path.get(i+1)));
			}
			
			mDbHelper.updateUserDistance(trainoid.DEFAULT_USER_ID, distance); // wrong this should add, not set the distance
			//mDbHelper.addUserDistance(trainoid.DEFAULT_USER_ID, distance);
			//mDbHelper.addUserTime(trainoid.DEFAULT_USER_ID, time);


			mDbHelper.setTransactionSuccessful();
		}
		catch (SQLException e) {}
		finally
		{
			mDbHelper.endTransaction();
		}

		mDbHelper.close();

		Toast.makeText(mCtx, "Track Saved correctly", Toast.LENGTH_SHORT).show();

		return (mTrackId > 0);
	}

	public void destroy()
	{
		path.clear();
		pathPositions.clear();
	}
}
